home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-20 / pmpsrc11.zip / PMP.C < prev    next >
Text File  |  1991-07-30  |  20KB  |  839 lines

  1. /*
  2.     pmp.c -- main program
  3.  
  4.   Poor Man's Packet (PMP)
  5.   Copyright (c) 1991 by Andrew C. Payne    All Rights Reserved.
  6.  
  7.   Permission to use, copy, modify, and distribute this software and its
  8.   documentation without fee for NON-COMMERCIAL AMATEUR RADIO USE ONLY is hereby
  9.   granted, provided that the above copyright notice appear in all copies.
  10.   The author makes no representations about the suitability of this software
  11.   for any purpose.  It is provided "as is" without express or implied warranty.
  12.  
  13.     July, 1989
  14.     Andrew C. Payne
  15. */
  16.  
  17. /* ----- Includes ----- */
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <conio.h>
  21. #include <alloc.h>
  22. #include <mem.h>
  23. #include <bios.h>
  24. #include <dos.h>
  25. #include <io.h>
  26. #include <ctype.h>
  27. #include <time.h>
  28. #include <string.h>
  29.  
  30. #define EXTERN
  31. #include "keys.h"
  32. #include "pmp.h"
  33. #include "ports.h"
  34.  
  35. int    holdmode;
  36.  
  37. /* ----- Title Screen ----- */
  38.  
  39. /* TitleScreen()
  40.     Shows the title screen.
  41. */
  42. static void TitleScreen(void)
  43. {
  44.     clrscr();
  45.     normal();
  46.     cprintf("     ▄▄▄▄▄▄▄                                                        ▄▄▄▄▄▄▄\r\n");
  47.     cprintf("     ▄▄▄▄▄▄▄                                                        ▄▄▄▄▄▄▄\r\n");
  48.     cprintf("     ▄▄▄▄▄▄▄      ▓▓▓▓▓▓▓▓         ▓▓     ▓▓          ▓▓▓▓▓▓▓▓      ▄▄▄▄▄▄▄\r\n");
  49.     cprintf("     ▄▄▄▄▄▄▄      ▓▓     ▓▓       ▓▓▓▓   ▓▓▓▓         ▓▓     ▓▓     ▄▄▄▄▄▄▄\r\n");
  50.     cprintf("     ▄▄▄▄▄▄▄      ▓▓     ▓▓       ▓▓ ▓▓ ▓▓ ▓▓         ▓▓     ▓▓     ▄▄▄▄▄▄▄\r\n");
  51.     cprintf("     ▄▄▄▄▄▄▄      ▓▓▓▓▓▓▓▓        ▓▓  ▓▓▓  ▓▓         ▓▓▓▓▓▓▓▓      ▄▄▄▄▄▄▄\r\n");
  52.     cprintf("     ▄▄▄▄▄▄▄      ▓▓              ▓▓       ▓▓         ▓▓            ▄▄▄▄▄▄▄\r\n");
  53.     cprintf("     ▄▄▄▄▄▄▄      ▓▓              ▓▓       ▓▓         ▓▓            ▄▄▄▄▄▄▄\r\n");
  54.     cprintf("     ▄▄▄▄▄▄▄      ▓▓ oor          ▓▓       ▓▓ an's    ▓▓ acket      ▄▄▄▄▄▄▄\r\n");
  55.     cprintf("     ▄▄▄▄▄▄▄                                                        ▄▄▄▄▄▄▄\r\n\n");
  56.     bright();
  57.     cprintf("                A Complete Packet Radio Program For The IBM PC\r\n\n");
  58.     normal();
  59.     cprintf("                         Version %s of %s \r\n\n\n",VERSION,__DATE__);
  60.     cprintf("                           By Andrew C. Payne, N8KEI\r\n");
  61.     cprintf("                  with special thanks to Kevin Feeney, WB2EMS\r\n\n");
  62.     cprintf("                       Copyright (c) 1989, 1990, 1991 ACP\r\n");
  63.     cprintf("                              All rights reserved.\r\n");
  64. }
  65.  
  66. /* ----- Subroutines ----- */
  67.  
  68. /* stoupper(s)
  69.     Convert string to upper case.
  70. */
  71. void stoupper(char *s)
  72. {
  73.     while(*s) {
  74.         *s = toupper(*s);
  75.         s++;
  76.     }
  77. }
  78.  
  79. /* wait()
  80.     Prompts user for keystroke.
  81. */
  82. void wait(void)
  83. {
  84.     bright();
  85.     gotoxy(1,25);
  86.     cprintf("                     ----- Press any key to continue ------");
  87.     (void)getkey();
  88. }
  89.  
  90. /* WaitKey(p)
  91.     Waits for a keystroke, calling PeriodicHook() while waiting.
  92.     Returns keystroke.  If 'p' is non-zero, then a prompt is shown
  93.     on line 'p'.
  94. */
  95. KEY WaitKey(int prompt)
  96. {
  97.     if(prompt)
  98.         CenterTitle(prompt,"  Press any key to resume  ");
  99.  
  100.     while(!keypressed())
  101.         PeriodicHook();
  102.  
  103.     return getkey();
  104. }
  105.  
  106. /* ----- Sound Control ----- */
  107.  
  108. /* StartSound(freq,time)
  109.     Starts a sound of the given frequency and duration (in 50 ms BIOS
  110.     clock ticks).
  111. */
  112. void StartSound(int freq, int time)
  113. {
  114.     if(Sound) {
  115.         sound(freq);
  116.         SoundEnd = BiosTime() + time;
  117.     }
  118. }
  119.  
  120. /* ----- Upper Level User Commands ------ */
  121.  
  122. /* DoHelp()
  123.     Handles the help screen.
  124. */
  125. void DoHelp(void)
  126. {
  127.     SaveScreen(TRUE,TRUE);
  128.     CenterTitle(1,"   PMP Help   ");
  129.     GotoXY(1,2);
  130.     _uputs(NormalAttr,"\n");
  131.     _uputs(NormalAttr,"│   ALT-C  Connect                           F1-F6   User defined macros\n");
  132.     _uputs(NormalAttr,"│   ALT-B  Send Beacon\n");
  133.     _uputs(NormalAttr,"│   ALT-D  Disconnect\n");
  134.     _uputs(NormalAttr,"│   ALT-H  Show help (this screen)           UP,DOWN Scrollback line at a time\n");
  135.     _uputs(NormalAttr,"│   ALT-J  Screen shapshot to file           PGUP/DN Scrollback page at a time\n");
  136.     _uputs(NormalAttr,"│   ALT-L  Download/capture a text file\n");
  137.     _uputs(NormalAttr,"│   ALT-N  Nodes recently heard\n");
  138.     _uputs(NormalAttr,"│   ALT-P  Pause screen\n");
  139.     _uputs(NormalAttr,"│   ALT-S  Show system status\n");
  140.     _uputs(NormalAttr,"│   ALT-U  Upload a text file\n");
  141.     _uputs(NormalAttr,"│   ALT-W  Write scrollback to disk\n");
  142.     _uputs(NormalAttr,"│   ALT-X  Exit PMP\n\n");
  143.     _uputs(NormalAttr,"│   ────────────────────────────────────────────────────────────────────────\n");
  144.     _uputs(NormalAttr,"│        Comments, questions, and money to:\n\n");
  145.     _uputs(NormalAttr,"│              Andrew C. Payne\n");
  146.     _uputs(NormalAttr,"│              Route 3, Box 78-Q\n");
  147.     _uputs(NormalAttr,"│              Berkeley Springs, WV  25411");
  148.     (void)WaitKey(23);
  149.     RestoreScreen();
  150. }
  151.  
  152. /* DoDebug()
  153.     Toggle debug mode on and off.
  154. */
  155. void DoDebug(void)
  156. {
  157.     DebugMode = !DebugMode;
  158.     putstring(1,25,1,InvAttr, DebugMode ? "■" : " ");
  159. }
  160.  
  161. /* DoConnect()
  162.     Prompts user for connect path, starts connection.
  163. */
  164. static void DoConnect(void)
  165. {
  166.     char    path[80];
  167.  
  168. /* if we are disconnected, prompt for connect path and initiate connect */
  169.     if(AX25_Control.state == DISCONNECTED) {
  170.         if(GetInput("Connect to --> ",path,60)) {
  171.             memcpy(&AX25_Control.header.source,
  172.                 &MyCall,sizeof(struct ax25_addr));
  173.             AX25_Control.header.pid = PID_TEXT;
  174.             AX25_Control.type = TEXT;
  175.             if(SetAX25Path(path,&AX25_Control.header))
  176.                 AX25_Open();
  177.         }
  178.     }
  179. }
  180.  
  181. /* DoStatus()
  182.     Shows the status of the node, primarily the health counters.
  183. */
  184. static void DoStatus(void)
  185. {
  186.     char    s[80];
  187.     long    t;
  188.     struct tm    *tm;
  189.     int    hours,minutes,secs;
  190. #ifdef TRACE
  191.     extern int    nlogs;
  192. #endif
  193.     SaveScreen(TRUE,TRUE);
  194.     CenterTitle(1,"   PMP Status   ");
  195.     GotoXY(1,4);
  196.     time(&t);
  197.     tm = localtime(&t);
  198.     sprintf(s,"│      Status at %02d/%02d/%02d %02d:%02d:%02d  ",
  199.         tm->tm_mon+1, tm->tm_mday, tm->tm_year, tm->tm_hour,
  200.         tm->tm_min, tm->tm_sec);
  201.     _uputs(NormalAttr,s);
  202.     t -= StartTime;
  203.     secs = t % 60;
  204.     t /= 60;
  205.     minutes = t % 60;
  206.     t /= 60;
  207.     hours = t % 24;
  208.     t /= 24;
  209.     sprintf(s,"    Uptime %d %02d:%02d:%02d\n\n",
  210.         (int)t, hours, minutes, secs);
  211.     _uputs(NormalAttr,s);
  212.     sprintf(s,"│      %8ld good frames received\n",RXCount);
  213.     _uputs(NormalAttr,s);
  214.     sprintf(s,"│      %8ld framing errors\n",RXFrameErr);
  215.     _uputs(NormalAttr,s);
  216.     sprintf(s,"│      %8ld checksum errors\n\n",RXCRCErr);
  217.     _uputs(NormalAttr,s);
  218.     sprintf(s,"│      %8ld receive queue overflows\n",RXQOverflow);
  219.     _uputs(NormalAttr,s);
  220.     sprintf(s,"│      %8ld receive buffer overflows\n",RXBOverflow);
  221.     _uputs(NormalAttr,s);
  222.     sprintf(s,"│      %8ld REJ frames received\n",RXREJ);
  223.     _uputs(NormalAttr,s);
  224.     sprintf(s,"│      %8ld FRMR frames received\n\n",RXFRMR);
  225.     _uputs(NormalAttr,s);
  226.     sprintf(s,"│      %8ld frames transmitted\n\n",TXCount);
  227.     _uputs(NormalAttr,s);
  228. #ifdef TRACE
  229.     sprintf(s,"│      %8ld frames in trace log\n\n",(long)nlogs);
  230.     _uputs(NormalAttr,s);
  231. #endif
  232.     sprintf(s,"│  %12ld bytes free\n\n",coreleft());
  233.     _uputs(NormalAttr,s);
  234.  
  235.     if(Capturing()) {
  236.         sprintf(s,"│       Capturing to %s (%ld bytes captured)",
  237.             CaptureFile, CaptureSize);
  238.         _uputs(NormalAttr,s);
  239.     }
  240.  
  241.     (void)WaitKey(23);
  242.     RestoreScreen();
  243. }
  244.  
  245. /* DoPause()
  246.     Pause the screen.
  247. */
  248. void DoPause(void)
  249. {
  250.     SaveScreen(TRUE,FALSE);
  251.     (void)WaitKey(23);
  252.     RestoreScreen();
  253. }
  254.  
  255. /* DoUpload()
  256.     Uploads a file.
  257.  
  258.     Crude first version, error handling sucks.
  259. */
  260. void DoUpload(void)
  261. {
  262.     char    fname[40];        /* file name to upload */
  263.     char    inbuf[256];        /* input buffer */
  264.     char    text[90];        /* temp text area */
  265.     long    filesize;        /* length of file in bytes */
  266.     long    starttime;        /* start time of upload */
  267.     int    uploadtime;        /* time used to upload */
  268.     FILE    *upfile;
  269.     int    cursor;
  270.     int    len;            /* # of bytes acutally read */
  271.  
  272. /* can't upload unless connected */
  273.     if(!Connected()) {
  274.         sound(400);
  275.         delay(200);
  276.         nosound();
  277.         return;
  278.     }
  279.  
  280. /* get filename, open file */
  281.     if(GetInput("Upload what file? --> ",fname,40)) {
  282.         if(!*fname)
  283.             return;
  284.  
  285.         stoupper(fname);
  286.         upfile = fopen(fname,"r");
  287.         if(upfile == NULL) {    /* error on open */
  288.             uprintf(InvAttr,"  Error opening '%s' : %s  \n",fname, sys_errlist[errno]);
  289.             return;
  290.         }
  291.  
  292. /* show upload status */
  293.         filesize = filelength(fileno(upfile));
  294.         cursor = cursave();
  295.         curoff();
  296.         sprintf(text,"    Uploading %-40s   Press <ESC> to abort",fname);
  297.         putstring(1,24,80,InvAttr,text);
  298.         starttime = BiosTime();
  299.  
  300. /* read lines from file */
  301.         while(len = fread(inbuf, 1, 256, upfile)) {
  302.  
  303. /* wait for space in AX.25 queue, then enqueue the data */
  304.             do {
  305.                 PeriodicHook();        /* wait to empty */
  306.                 if(keypressed() && (getkey() == ESC)) {
  307.                     Notify("    Upload aborted.");
  308.                     goto done;
  309.                 }
  310.             } while(AX25QFull());
  311.  
  312.             LinkSend((byte *)inbuf, len);        /* send the data */
  313.             uputtext(BrightAttr, inbuf, len);
  314.         }
  315.         uploadtime = (BiosTime() - starttime) / BIOSSEC;
  316.         if(uploadtime == 0)
  317.             uploadtime = 1;
  318.  
  319. /* if terminated for any reason other than EOF, handle error */
  320.         if(ferror(upfile)) {
  321.             uprintf(InvAttr," Error reading '%s' : %s  \n",
  322.                 fname, sys_errlist[errno]);
  323.         } else {
  324.             if(Sound) {            /* two beeps */
  325.                 sound(2600);
  326.                 delay(100);
  327.                 nosound();
  328.                 delay(50);
  329.                 sound(2600);
  330.                 delay(100);
  331.                 nosound();
  332.             }
  333.             sprintf(text,"    Upload complete.  (%d seconds for %ld bytes = %ld bytes/sec)",
  334.                 uploadtime, filesize, (long)(filesize/uploadtime));
  335.             Notify(text);
  336.         }
  337. done:
  338.         clear_area(24,1,80);        /* clean up */
  339.         currest(cursor);
  340.         fclose(upfile);
  341.     }
  342. }
  343.  
  344. /* DoCapture()
  345.     Toggles file capture (log to disk).
  346.  
  347.     Note:   The test for a file aready existing could be cleaned up
  348.         using 'access'.
  349. */
  350. void DoCapture(void)
  351. {
  352.     char    fname[41];        /* capture filename */
  353.     char    text[80];               /* temp text area */
  354.     FILE    *test;
  355.  
  356. /* If already capturing, close file */
  357.     if(Capturing()) {
  358.         sprintf(text,"    Closing capture file  %s   (%ld bytes)",
  359.             CaptureFile, CaptureSize);
  360.         Notify(text);
  361.         CloseCapture();
  362.         putstring(60,25,3,StatusAttr,"");
  363.         return;
  364.     }
  365.  
  366. /* get filename */
  367.     if(GetInput("Capture file? --> ",fname,40)) {
  368.         if(!*fname)
  369.             return;
  370.  
  371.         if((test = fopen(fname,"r")) != NULL) {
  372.             fclose(test);
  373.             if(!GetInput("File already exists.  Overwrite? [Y/N]",text,2))
  374.                 return;
  375.             if(toupper(*text) != 'Y')
  376.                 return;
  377.         }
  378.         stoupper(fname);
  379.         OpenCapture(fname);
  380.         putstring(60,25,3,StatusAttr,"Cap");
  381.     }
  382. }
  383.  
  384. /* DoSnapshot()
  385.     Write a snapshot of the current screen to a file.
  386. */
  387. void DoSnapshot(void)
  388. {
  389.     char    fname[41];        /* capture snapshot */
  390.     FILE    *test;
  391.     char    temp[160];        /* temp area */
  392.     char    line[81];        /* output line */
  393.     int    i,l;            /* screen line */
  394.     char    *p,*q;
  395.  
  396. /* open snapshot file*/
  397.     if(!GetInput("Snapshot to what file? --> ",fname,40))
  398.         return;
  399.     if(!*fname)
  400.         return;
  401.  
  402.     if((test = fopen(fname,"r")) != NULL) {
  403.         fclose(test);
  404.         if(!GetInput("File already exists.  Overwrite? [Y/N]",line,2))
  405.             return;
  406.         if(toupper(*line) != 'Y')
  407.             return;
  408.     }
  409.     if((test = fopen(fname,"w")) == NULL) {
  410.         Notify("    Can't open snapshot file.");
  411.         return;
  412.     }
  413.  
  414. /* write contents of screen to file */
  415.     for(l=1; l<24; l++) {
  416.         gettext(1,l,80,l,temp);
  417.         q = line;
  418.         p = temp;
  419.         for(i=0; i<80; i++) {    /* extract contents */
  420.             *q++ = *p++;
  421.             p++;
  422.         }
  423.         do {            /* trim line */
  424.             q--;
  425.         } while(q >= line && (*q == '\0' || *q == ' '));
  426.         *++q = '\n';
  427.         *++q = '\0';
  428.         fputs(line, test);    /* should error check this */
  429.     }
  430.     fclose(test);
  431. }
  432.  
  433. /* DoWrite()
  434.     Writes the contents of the scrollback buffer to the file specified.
  435. */
  436. void DoWrite(void)
  437. {
  438.     char    fname[41];        /* capture snapshot */
  439.     FILE    *test;
  440.     char    line[81];        /* output line */
  441.  
  442. /* open snapshot file*/
  443.     if(!GetInput("Write scrollback buffer to what file? --> ",fname,40))
  444.         return;
  445.     if(!*fname)
  446.         return;
  447.  
  448.     if((test = fopen(fname,"r")) != NULL) {
  449.         fclose(test);
  450.         if(!GetInput("File already exists.  Overwrite? [Y/N]",line,2))
  451.             return;
  452.         if(toupper(*line) != 'Y')
  453.             return;
  454.     }
  455.     WriteScrollback(fname);
  456. }
  457.  
  458. /* ----- Main Loop ----- */
  459.  
  460. /* PeriodicHook()
  461.     When in an idle loop, this routine should be called as much as
  462.     possible.  If the carrier is down, goes to RX, handles timers
  463.     and flushes the TX queue.
  464. */
  465. void PeriodicHook(void)
  466. {
  467.     long    t;
  468.  
  469. /* Go to RX if a carrier is detected */
  470.     while(RXCarrier()) {
  471.         if(RXLevel1())         /* receive incoming */
  472.             RXProcess();    /* process incoming */
  473.         Pwait = 0;
  474.     }
  475.  
  476. /* process AX.25 link transmit items, if any */
  477.     AX25_Flush();
  478.  
  479. /* check for expired timers */
  480.     t = BiosTime();
  481.     if(AX25_Control.t1 != 0 && AX25_Control.t1 <= t)
  482.             AX25_Expire(1);
  483.     if(AX25_Control.t3 != 0 && AX25_Control.t3 <= t)
  484.             AX25_Expire(3);
  485.     if(SoundEnd && t >= SoundEnd) {        /* sound timeout */
  486.         nosound();
  487.         SoundEnd = 0;
  488.     }
  489.     if(BeaconEnd && t >= BeaconEnd) {    /* beacon timeout */
  490.         SendBeacon();
  491.         StartBeacon();
  492.     }
  493.  
  494. /* do p-persistence, and flush anything in the TX queue */
  495.     if(Pwait == 0 || t > Pwait) {    /* attempt transmission */
  496.         if(rand() < Ppersist) {    /* we are a go? */
  497.             Pwait = 0;
  498.             TXQEmpty();        /* Transmit! */
  499.         } else
  500.             Pwait = t + Slottime;    /* wait a bit */
  501.     }
  502. }
  503.  
  504. /* MainLoop()
  505.     Main command handling loop.
  506. */
  507. static void MainLoop(void)
  508. {
  509.     char    buf[82];        /* input buffer */
  510.     char    temp;            /* temp character storage */
  511.     int    p;            /* position in input buffer */
  512.     KEY    k;            /* keypress */
  513.     byte    c;
  514.     int    state;            /* current connected state */
  515.     int    scrollback;        /* TRUE if scrolling back */
  516.     int    i;
  517.  
  518. /* initalize */
  519.     InitKeybuffer();
  520.     scrollback = FALSE;
  521.     p = 0;
  522.     gotoxy(1,24);
  523.     state = Connected();
  524.  
  525. /* main loop */
  526.     while(TRUE) {
  527.  
  528. /* loop until keypress or change in state */
  529.         while(!keypressed() && (state == Connected()))
  530.             PeriodicHook();        /* do RX, TX, timers */
  531.         state = Connected();
  532.  
  533. /* handle the cursor */
  534.         if(Connected())        /* if connected, show cursor */
  535.             curon();
  536.         else {
  537.             if(p) {            /* clear any text */
  538.                 clear_area(24,1,80);
  539.                 p = 0;
  540.             }
  541.             curoff();
  542.         }
  543.  
  544. /* handle any user keystrokes */
  545.         while(k = Nextkey()) {
  546.  
  547. /* exit scrollback mode, if appropriate */
  548.             if(scrollback && k != UP && k != DOWN
  549.                 && k != PGDN && k != PGUP && k != HOME) {
  550.                 EndScrollback();
  551.                 scrollback = FALSE;
  552.             }
  553.  
  554. /* ASCII keypress, show on bottom line */
  555.             if((c = asciicode(k)) && Connected()) {
  556.                 bright();
  557.                 switch(c) {
  558.                     case '\r':        /* send */
  559.                         buf[p++] = '\n';
  560.                         buf[p] = '\0';
  561.                         uputs(BrightAttr, buf);
  562.                         LinkSend((byte *)buf, p);
  563.                         clear_area(24,1,80);
  564.                         p = 0;
  565.                         break;
  566.                     case '\b':        /* backspace */
  567.                         if(p>0) {
  568.                             cprintf("\b \b");
  569.                             p--;
  570.                         }
  571.                         break;
  572.                     case ' ':        /* test for autowrap */
  573.                         if(AutoWrap && p > AutoWrap) {
  574.                             i = p-1;
  575.                             while(i && buf[i] != ' ')
  576.                                 i--;
  577.                             if(i) {    /* wrap word */
  578.                                 buf[i++] = '\n';
  579.                                 temp = buf[i];
  580.                                 buf[i] = '\0';
  581.                                 LinkSend((byte *)buf,i);
  582.                                 uputs(BrightAttr,buf);
  583.                                 buf[i] = temp;
  584.                                 buf[p] = '\0';
  585.                                 strcpy(buf, buf+i);
  586.                                 p -= i;
  587.                                 clear_area(24,1,80);
  588.                                 if(p)
  589.                                     putstring(1,24,80,BrightAttr,buf);
  590.                             }
  591.                         }
  592.                         /* note fall through */
  593.                     default:        /* char */
  594.                         if(p < 79)
  595.                             putch(buf[p++] = c);
  596.                 }
  597.  
  598. /* else, function key */
  599.             } else {
  600.                 switch(k) {
  601.                     case DOWN:        /* scroll */
  602.                         if(scrollback) {
  603.                             if(MoveScrollback(1)) {
  604.                                 EndScrollback();
  605.                                 scrollback = FALSE;
  606.                             }
  607.                         }
  608.                         break;
  609.                     case UP:        /* scroll */
  610.                         if(!scrollback)
  611.                             scrollback = StartScrollback();
  612.                         if(scrollback)
  613.                             MoveScrollback(-1);
  614.                         break;
  615.                     case PGUP:        /* scroll */
  616.                         if(!scrollback)
  617.                             scrollback = StartScrollback();
  618.                         if(scrollback)
  619.                             MoveScrollback(-23);
  620.                         break;
  621.                     case PGDN:        /* scroll */
  622.                         if(scrollback) {
  623.                             if(MoveScrollback(23)) {
  624.                                 EndScrollback();
  625.                                 scrollback = FALSE;
  626.                             }
  627.                         }
  628.                         break;
  629.                     case HOME:        /* scroll */
  630.                         if(!scrollback)
  631.                             scrollback = StartScrollback();
  632.                         if(scrollback)
  633.                             MoveScrollback(-32000);
  634.                         break;
  635.                     case ALTX:        /* exit */
  636.                         if(Connected()) {
  637.                             sound(400);
  638.                             delay(200);
  639.                             nosound();
  640.                         } else
  641.                             return;
  642.                         break;
  643.                     case ALTB:        /* beacon */
  644.                         SendBeacon();
  645.                         break;
  646.                     case ALTC:        /* connect */
  647.                         DoConnect();
  648.                         break;
  649.                     case ALTD:        /* discnnct */
  650.                         AX25_Close();
  651.                         break;
  652.                     case ALTH:        /* help */
  653.                         DoHelp();
  654.                         break;
  655.                     case ALTJ:        /* snapshot */
  656.                         SaveMessage();
  657.                         DoSnapshot();
  658.                         RestoreMessage();
  659.                         state = -1;
  660.                         break;
  661.                     case ALTN:        /* nodes heard */
  662.                         DoHeard();
  663.                         break;
  664.                     case ALTP:        /* pause */
  665.                         DoPause();
  666.                         break;
  667.                     case ALTS:        /* node status */
  668.                         DoStatus();
  669.                         break;
  670.                     case ALTU:        /* file upload */
  671.                         SaveMessage();
  672.                         DoUpload();
  673.                         RestoreMessage();
  674.                         state = -1;
  675.                         break;
  676.                     case ALTL:        /* file download/capture */
  677.                         SaveMessage();
  678.                         DoCapture();
  679.                         RestoreMessage();
  680.                         state = -1;
  681.                         break;
  682.                     case ALTW:        /* write scrollback */
  683.                         SaveMessage();
  684.                         DoWrite();
  685.                         RestoreMessage();
  686.                         state = -1;
  687.                         break;
  688.                     case F1:
  689.                         AddKeystrokes(fkeys[0]);
  690.                         break;
  691.                     case F2:
  692.                         AddKeystrokes(fkeys[1]);
  693.                         break;
  694.                     case F3:
  695.                         AddKeystrokes(fkeys[2]);
  696.                         break;
  697.                     case F4:
  698.                         AddKeystrokes(fkeys[3]);
  699.                         break;
  700.                     case F5:
  701.                         AddKeystrokes(fkeys[4]);
  702.                         break;
  703.                     case F6:
  704.                         AddKeystrokes(fkeys[5]);
  705.                         break;
  706.                     case F7:
  707.                         AddKeystrokes(fkeys[6]);
  708.                         break;
  709.                     case F8:
  710.                         AddKeystrokes(fkeys[7]);
  711.                         break;
  712.                     case F9:        /* toggle PASSALL */
  713.                         PassMode = !PassMode;
  714.                         break;
  715. #ifdef TRACE
  716.                     case F10:        /* debug */
  717.                         DoDebug();
  718.                         break;
  719. #endif
  720.                 }
  721.             }
  722.             gotoxy(p+1,24);
  723.         }
  724.     }
  725. }
  726.  
  727. /* ----- Error handling ----- */
  728.  
  729. /* OutOfMemory()
  730.     Gets called during initialization routines to show an out of
  731.     memory error.  Prompts for user keystroke and exits.
  732. */
  733. void OutOfMemory(void)
  734. {
  735.     cprintf("  Fatal Error -- Out of Memory!  ");
  736.     wait();
  737.     CRTExit();
  738.     exit(-1);
  739. }
  740.  
  741. /* usage()
  742.     Show the command line usage.
  743. */
  744. static void usage(void)
  745. {
  746.     printf("Usage:  PMP {-a} {-p<paramfile>}\n");
  747. }
  748.  
  749. /* ----- Main Program ----- */
  750.  
  751. void main(int argc, char **argv)
  752. {
  753.     int    i;
  754.  
  755. /* process command line parameters */
  756.     AutoMode = FALSE;
  757.     strcpy(ParamFname, "PMP.CFG");
  758.     for(i=1; i<argc; i++) {
  759.         if(argv[i][0] != '-') {
  760.             usage();
  761.             exit(-1);
  762.         } else switch(toupper(argv[i][1])) {
  763.             case 'A':
  764.                 AutoMode = TRUE;
  765.                 break;
  766.             case 'P':
  767.                 strcpy(ParamFname, argv[i]+2);
  768.                 break;
  769.             default:
  770.                 printf("Unknown switch: %s\n",argv[i]);
  771.                 usage();
  772.                 exit(0);
  773.         }
  774.     }
  775.  
  776. /* check to see if we've got enough memory to breathe */
  777.     if(coreleft() < 65536L) {
  778.         printf("Not enough free memory to run PMP.\n");
  779.         exit(-1);
  780.     }
  781.  
  782. /* Startup */
  783.     InitParameters();
  784.     TXKey(FALSE);        /* no transmitter */
  785.     CRTInit();
  786.     TitleScreen();
  787.  
  788. /* read the parameter file */
  789.     gotoxy(1,23);
  790.     inverse();        /* set up for errors */
  791.     if(ReadParameters()) {    /* if error reading parameter file */
  792.         wait();
  793.         CRTExit();
  794.         exit(-1);
  795.     }
  796.  
  797. /* initialize */
  798.     RXInit();        /* Initialize RX */
  799.     TXQInit();        /* Initialize TX */
  800.     AX25_Init();        /* Initialize AX25 LAPB */
  801.     HeardInit();        /* Initialize the heard lists */
  802.     InitCapture();        /* Initialize capture */
  803.  
  804.     if(!AutoMode)
  805.         wait();
  806.  
  807.  
  808.     time(&StartTime);
  809.     normal();
  810.     clrscr();
  811.     StatusLine();
  812.  
  813. #ifdef TRACE
  814.     LogInit();        /* Initialize the log */
  815.     DebugMode = FALSE;
  816.     DoDebug();
  817. #endif
  818.  
  819. #ifdef DEBUG
  820.     PassMode = FALSE;
  821. #endif
  822.     holdmode = FALSE;
  823.  
  824. /* crank up timers */
  825.     StartBeacon();
  826.     SoundEnd = 0;
  827.  
  828. /* doit! */
  829.     MainLoop();
  830.     if(Capturing())            /* close capture file */
  831.         DoCapture();
  832.  
  833. /* bye, bye, clean things up...  */
  834.     CRTExit();
  835. #ifdef TRACE
  836.     DumpLog();            /* dump the debug log */
  837. #endif
  838.     exit(0);
  839. }